package com.xuelang.pipeline.entry.pipeline;

import com.xuelang.pipeline.app.msg.MsgUserMessagesService;
import com.xuelang.pipeline.app.pipeline.PipelineService;
import com.xuelang.pipeline.client.msg.MsgConstant;
import com.xuelang.pipeline.client.msg.UserMessageSaveDTO;
import com.xuelang.pipeline.client.pipeline.dto.TriggerPipelineDTO;
import com.xuelang.pipeline.client.pipeline.enums.TriggerWayEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.List;

/**
 * 流水线接收git事件的webhook控制类
 *
 * @author : yixin.lys
 * @date : 2024-06-12 13:58
 **/
@Slf4j
@RestController
@RequestMapping("/webhook")
public class WebhookController {

    @Autowired
    private PipelineService pipelineService;

    @Autowired
    private MsgUserMessagesService msgUserMessagesService;

    @Value("${webhook.secret:}") // 使用占位符，允许 secret 为空
    private String webhookSecret;

    /**
     * 处理git事件的webhook接口
     * @param githubEvent github事件
     * @param gitlabEvent gitlab事件
     * @param signature 签名
     * @param payload 载荷
     * @param pipelineCode 流水线code
     * @return
     * @throws Exception
     */
    @PostMapping("/{pipelineCode}")
    public String handleWebhook(
            @RequestHeader(value = "X-GitHub-Event", required = false) String githubEvent,
            @RequestHeader(value = "X-Gitlab-Event", required = false) String gitlabEvent,
            @RequestHeader(value = "X-Hub-Signature-256", required = false) String signature,
            @RequestBody String payload, @PathVariable("pipelineCode") String pipelineCode) throws Exception {

        String event = (githubEvent != null) ? githubEvent : gitlabEvent;
        if (event == null) {
            return "Missing event header";
        }

        // 如果配置了 secret，则验证签名
        if (webhookSecret != null && !webhookSecret.isEmpty()) {
            if (!verifySignature(signature, payload)) {
                return "Invalid signature";
            }
        }

        String eventStr = event.toLowerCase();
        // 发送消息
        sendMsg(payload, pipelineCode, eventStr);
        // 执行触发
        switch (event.toLowerCase()) {
            case "push":
                handlePushEvent(payload, pipelineCode);
                break;
            case "merge request":
            case "merge_request":
                handlePullRequestEvent(payload, pipelineCode);
                break;
            default:
                handleUnknownEvent(payload, pipelineCode);
                break;
        }

        log.info("Webhook received");
        return "Webhook received";
    }

    private boolean verifySignature(String signature, String payload) throws Exception {
        if (signature == null || signature.isEmpty()) {
            return false;
        }
        String hashAlgorithm = "HmacSHA256";
        Mac mac = Mac.getInstance(hashAlgorithm);
        SecretKeySpec secretKey = new SecretKeySpec(webhookSecret.getBytes(), hashAlgorithm);
        mac.init(secretKey);
        byte[] hmac = mac.doFinal(payload.getBytes());
        String computedSignature = "sha256=" + Hex.encodeHexString(hmac);
        return computedSignature.equals(signature);
    }

    private void handlePushEvent(String payload, String pipelineCode) {
        log.debug("Handling push event: " + payload);
        // 触发对应流水线
        TriggerPipelineDTO reqDTO = TriggerPipelineDTO.builder().pipelineCode(pipelineCode).triggerType(TriggerWayEnum.EVENT.getValue()).build();
        pipelineService.triggerPipelineInstance(reqDTO);
    }

    private void handlePullRequestEvent(String payload, String pipelineCode) {
        log.debug("Handling pull request event: " + payload);
        // 触发对应流水线
        TriggerPipelineDTO reqDTO = TriggerPipelineDTO.builder().pipelineCode(pipelineCode).triggerType(TriggerWayEnum.EVENT.getValue()).build();
        pipelineService.triggerPipelineInstance(reqDTO);
    }

    private void handleUnknownEvent(String payload, String pipelineCode) {
        log.debug("Handling unknown event: " + payload);
        // 触发对应流水线
        TriggerPipelineDTO reqDTO = TriggerPipelineDTO.builder().pipelineCode(pipelineCode).triggerType(TriggerWayEnum.EVENT.getValue()).build();
        pipelineService.triggerPipelineInstance(reqDTO);
    }

    private void sendMsg(String payload, String pipelineCode, String event){
        List<String> toNotifyUserList = pipelineService.findPipelineNotifyReceiverList(pipelineCode);
        // 定时触发时记录消息
        UserMessageSaveDTO userMessageSaveDTO = new UserMessageSaveDTO();
        userMessageSaveDTO.setMsgType(MsgConstant.MSG_TYPE_TEXT);
        userMessageSaveDTO.setTitle("git事件触发");
        userMessageSaveDTO.setContent("流水线编码为：" + pipelineCode
                + " 的git事件已经触发; 事件类型：" + event
                + "; payload: " + payload);
        userMessageSaveDTO.setReceiveUserIds(toNotifyUserList);
        msgUserMessagesService.saveMessage(userMessageSaveDTO);
    }

}
